#include <stdio.h>
#include <iostream>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string>



using namespace std;
const int database = 1024;
const int argvnum = 64;
const int envnum = 64;
//全局的命令行参数列表
char* gargv[argvnum];
int gargc = 0;
int lastcode = 0;
//全局的环境变量
char* genv[envnum];

//全局的当前shell工作路径
char pwd[database];
char pwdenv[database];

string GetUserName()
{
    string s = getenv("USER");
    return s.empty()?"None":s;
}
string GetHostName()
{
    string s = getenv("HOSTNAME");
    return s.empty()?"None":s;
}
string GetPwd()
{
    if(nullptr == getcwd(pwd,sizeof(pwd)))return "None";
    snprintf(pwdenv,sizeof(pwdenv),"PWD=%s",pwd);
    putenv(pwdenv);
    return pwd;
}
string LastDir()
{
    string curr = GetPwd();
    if(curr == "/" || curr == "None")return curr;

    size_t pos = curr.rfind("/");
    if(pos == std::string::npos)return curr;
    return curr.substr(pos+1);
}
string MakeCommandLine()
{
    //[ljy@VM-16-3-centos 250226myshell]
    char cline[database];
   snprintf(cline,database,"[%s@%s %s]#",
           GetUserName().c_str(),GetHostName().c_str(),LastDir().c_str());
   return cline;

}

void PrintCommandLine()
{
    printf("%s",MakeCommandLine().c_str());
    fflush(stdout);
}
//2.读取指令
bool GetCommandLine(char* command_buffer,int size)
{
    //将用户输入的命令行，当作一个完整的字符串
    //ls -a -l
    char * ret = fgets(command_buffer,size,stdin);
    if(!ret)
    {
        return false;
    }
    command_buffer[strlen(command_buffer)-1] =  0;
    if(strlen(command_buffer) == 0)return false;
    return true;
}
//2.分析指令
void ParseCommandline(char* command_buffer,int len)
{
    (void)len;
    //以sep为分隔符取出每一个命令行参数
    memset(gargv,0,sizeof(gargv));
    gargc = 0;
    const char *sep = " ";
    gargv[gargc++] =strtok(command_buffer,sep);
    while((bool)(gargv[gargc++] = strtok(nullptr,sep)));
    gargc--;
    return ;
}

void debug()
{
    int i = 0;
    while(i<=gargc)
    {
        printf("%d:%s   ",i,gargv[i]);
        ++i;
    }
}
//3.执行指令
bool ExecuteCommand()
{
   pid_t id = fork();
   if(id < 0 )return false;
   if(id == 0)
   {
        //子进程
        //1.执行命令
        //cout<<"aaaaaaaaaaa"<<endl;
        //printf("AAAAAA\n");
        //execlp("ls","ls","-a",nullptr);
        execvp(gargv[0],gargv);
        //2.执行失败退出
        exit(1);
   }
   //父进程
    int status = 0;
    pid_t rid = waitpid(id,&status,0);
    if(rid > 0)
    {
        return true;
        if(WIFEXITED(status))
        {
            lastcode = WEXITSTATUS(status);
        }
        else 
        {
            lastcode = 100;
        }
    }
    return false;
}

void AddEnv(const char* item);

//shell自己执行的命令，本质是shell调用自己的函数
bool CheckAndExecBuiltCommand()
{
    if(strcmp(gargv[0],"cd") == 0)
    {
        if(gargc == 2)
        {
            chdir(gargv[1]);
            lastcode = 0;
        }
        else
        {
            lastcode = 1;
        }
        return true;
    }
    else if(strcmp(gargv[0],"expert") == 0)
    {
        if(gargc == 2)
        {
            AddEnv(gargv[1]);
            lastcode = 0;
        }
        else
        {
            lastcode = 2;
        }
        return true;
    }
    else if(strcmp(gargv[0],"env") == 0)
    {
        int i = 0 ; 
        while(genv[i])
        {
            printf("%s\n",genv[i++]);
        }
        lastcode = 0;
        return true;
    }
    else if(strcmp(gargv[0],"echo") == 0)
    {
        if(gargc == 2)
        {
            if(gargv[1][0] == '$')
            {
                if(gargv[1][1] == '?')
                {
                    printf("%d\n",lastcode);
                }
            }
            else
            {
                printf("%s\n",gargv[1]);
            }
            lastcode = 0;
        }
        else
        {
            lastcode = 3;
        }
        return true;
    }
    return false;
}
void InitEnv()
{
    extern char ** environ;
    int index = 0;
    while(environ[index])
    {
        genv[index] = (char*)malloc(strlen(environ[index])+1);
        strncpy(genv[index],environ[index],strlen(environ[index])+1);
        index++;
    }
    genv[index] =nullptr;
}
void AddEnv(const char* item)
{
    int index = 0;
    while(genv[index])
    {
        ++index;
    }

    genv[index] = (char*)malloc(strlen(item)+1);
    strncpy(genv[index],item,strlen(item)+1);
    genv[++index] = nullptr;
}
int main()
{
    InitEnv();
    while(true)
    {
        //0.打印命令提示符
        PrintCommandLine();
        char commandline[database];
        //1.读取指令
        GetCommandLine(commandline,database);
        //2.分析指令
        ParseCommandline(commandline,database);
        //debug();
        //执行内建指令
        if(CheckAndExecBuiltCommand())
        {
            continue;
        }
        //3.执行指令
        ExecuteCommand();
    }
    return 0;
}
